<?php
class uploadFileException extends Exception {

}

class UploadFile {
	
    protected $uploadPath; 	// 上传文件存放路径 
    
    protected $oldFileInfo;	// 原文件信息 如:$_FIELS['userfile'] 
    
	protected $newFileName;	// 上传文件名称
	
	protected $fileNum;		// 要上传的文件个数
	
	protected $maxUploadSize; // 文件最大上传字节数
	
	protected $allowUploadType; // 允许上传的文件类型
	
	protected $errorMsg;
	
	public function __construct($upload_path='') {
		$this->setUploadPath($upload_path);
		$this->fileIsRename = 0;	
		$this->setAllowUploadType(array('image/jpeg', 'image/jpg', 'image/gif', 'image/png', 'image/pjpeg', 'application/octet-stream'));
		$this->setMaxUplaodSize(1024*1024*2); // 1MB
		$this->setIsRename(true);
		$this->errorMsg = array();
	}
	
	public static function formatFileSize($size) {
		if ($size < 1024) {
			$size = $size.'B';
		}else if ($size >= 1024 && $size < 1024*1024) {
			$size = round($size / 1024, 2).'KB';
		}else if ($size >= 1024*1024 && $size < 1024*1024*1024) {
			$size = round($size / (1024*1024), 2).'MB'; 
		}else {
			$size = round($size / (1024*1024*1024), 2).'GB';
		}
		return $size;
	}
	
	public static function mkdirs($dir, $len=0) {
		if (strpos($dir, '\\') !== false) $dir = str_replace('\\', '/', $dir);
		if ($dir[strlen($dir)-1] != '/') $dir.='/';
		if (!is_dir($dir)) {
			$len2 = strpos($dir, '/', $len);
			$dir2 = substr($dir, 0, $len2); 
			// drwxrw-rw-
			if (!is_dir($dir2) && !mkdir($dir2, 0777)) return false;
			self::mkdirs($dir, $len2+1);
		}
		return true;
	}
	
	public function setUploadPath($upload_path) {
		if (strpos($upload_path, '\\') !== false) $upload_path = str_replace('\\', '/', $upload_path);
		if ($upload_path[strlen($upload_path)-1] != '/') $upload_path .= '/';
		$this->uploadPath = $upload_path;
		if (!self::mkdirs($this->uploadPath)) {
			throw new uploadFileException('文件上传目录('.$this->uploadPath.')无法创建!');
		}
	}
	
	public function setNewFileName($new_filename) {
		$this->newFileName = $new_filename;
	}
	
	public function setIsRename($isrename) {
		$this->isRename = $isrename !== false ? true : false;
	}
	
	public function setOldFileInfo($old_fileinfo) {
		$this->oldFileInfo = $old_fileinfo;
		$this->setFileNum(count($old_fileinfo['name']));
	}
	
	public static function getFileExt($old_filename) {
		$fileInfoArr = pathinfo($old_filename);
		return strtolower($fileInfoArr['extension']);
	}
	
	public function setAllowUploadType($allowUploadType = '') {
		if (empty($allowUploadType)) return false;
		$this->allowUploadType = $allowUploadType;
	}

	protected function setFileNum($num) {
		if ($num < 1) throw new uploadFileException('上传文件个数不正常!');
		$this->fileNum = $num;
	}
	
	protected function checkUploadFileType($file_type, $file_name) {
		if (!in_array($file_type, $this->allowUploadType)) {
			$this->errorMsg[] = '上传文件('.$file_name.')文件类型不符合!';
		}
	}
	
	public function setMaxUplaodSize($max_size) {
		$this->maxUploadSize = $max_size;
	}
	
	protected function checkFileSize($file_size, $file_name) {
		if ($file_size > $this->maxUploadSize) {
			$this->errorMsg[] = '上传文件('.$file_name.')大小超过设定最大值('.self::formatFileSize($this->maxUploadSize).')!';
		}
	}
	
	protected function checkIsUploadedFile($tmp_name, $file_name) {
		if (!is_uploaded_file($tmp_name)) {
			$this->errorMsg[] = '上传文件("'.$file_name.'")上传模式非HTTP POST方式!';
		}
	}
	
	protected function checkUploadIsError($error_code, $file_name) {
		$msg = '';
		switch ($error_code) {
			case UPLOAD_ERR_INI_SIZE:   $msg = '上传文件字节数过大!'; break;
			case UPLOAD_ERR_PARTIAL: 	$msg = '文件只有部分被上传!'; break;
			case UPLOAD_ERR_NO_FILE: 	$msg = '没有文件被上传!'; break;
			case UPLOAD_ERR_NO_TMP_DIR: $msg = '找不到临时文件夹!'; break;
			case UPLOAD_ERR_CANT_WRITE: $msg = '文件写入失败!'; break;	
		}
		
		if (!empty($msg)) {
			throw new uploadFileException($msg);
		}
	}
	
	protected function checkFileUpload() {
		$file = $this->oldFileInfo;
		for ($i=0; $i<$this->fileNum; $i++) {
			$this->checkUploadIsError($file['error'][$i], $file['name'][$i]);			
			$this->checkUploadFileType($file['type'][$i], $file['name'][$i]);
			$this->checkFileSize($file['size'][$i], $file['name'][$i]);
			$this->checkIsUploadedFile($file['tmp_name'][$i], $file['name'][$i]);
		}
		
		if (count($this->errorMsg) > 0) {
			throw new uploadFileException(implode('\n', $this->errorMsg));
		}
	}
	
	public function upload($file_infos) {
		if (!is_array($file_infos['name'])) {
			$file_infos = array(
					'name' => array($file_infos['name']),
					'type' => array($file_infos['type']),					
					'tmp_name'=> array(stripslashes($file_infos['tmp_name'])),
					'error' => array($file_infos['error']),
					'size' => array($file_infos['size']),
			);
		}
		$this->setOldFileInfo($file_infos);
		$this->setFileNum(count($file_infos['name']));
		$this->checkFileUpload();
	
		$full_filenames = array();
		for ($i=0; $i<$this->fileNum; $i++) {
			$file_ext = $this->getFileExt($file_infos['name'][$i]);
			if ($this->isRename === false) {
				$full_filenames[] = $full_filename = $this->uploadPath . $file_infos['name'][$i];
			}else {
				$full_filenames[] = $full_filename = $this->uploadPath . md5(time().mt_rand(1, 9999)).'.'.$file_ext;
			}
			if (!move_uploaded_file($file_infos['tmp_name'][$i], $full_filename)) {
				throw new uploadFileException('移动文件('.$file_infos['name'][$i].')失败!');
			}
		}
		return $full_filenames;
	}
}

